/*
 * TopicController.java
 * purpose : Controller
 * 
 * @version 1.0 04/28/11
 * @author Ahmed Mustafa Taha
 */

package controllers;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import com.sun.org.apache.bcel.internal.generic.NEW;
import com.sun.xml.internal.ws.developer.UsesJAXBContext;

import play.data.validation.Required;
import play.data.validation.Validation;
import play.db.jpa.GenericModel.JPAQuery;
import play.mvc.Controller;

import models.EEntity;
import models.Idea;
import models.EEntity;

import models.ActionLog;
import models.IdeaRating;
import models.Notification;
import models.Tag;
import models.Organization;
import models.Role;
import models.RoleInOrganization;
import models.Topic;
import models.TopicRating;
import models.User;

public class TopicController extends Controller {

	/**
	 * Deletes a video with the code video from the idea with the given ID.Adds the action
	 * done to the action log.If the user is null, ie is no logged in , he will be redirected
	 * to the not logged in page.
	 * 
	 * 
	 * @author Hesham Massoud
	 * 
	 * @param ideaId
	 *            to get the ID of the idea which contains the video that will
	 *            be removed.
	 * 
	 * @param video
	 *            the code of the video that is going to be removed.
	 */
	public static void removeVid(String video, long ideaId) {
		User user = User.getUserInfo(session.get("username"));
		if(user!=null){
		Idea idea = Idea.findById(ideaId);
		notFoundIfNull(idea);
		idea.videos.remove(video);
		idea.save();
		String actionMsg = user.userName
		+ " removed a video from the idea "+ idea.title + ".";
		new ActionLog(actionMsg, user, null).save();
		
		flash.success("Video Removed Successfully.");
		IdeaController.viewAddVideo(idea.id);
		}
		else{
			render("Application/notLoggedIn.html");
		}
	}

	/**
	 * 
	 * Checks whether the given video URL is a valid you tube video , if its not
	 * gives an error message , the method takes the video code from the URL
	 * given and adds it to the list of videos for the idea with the given
	 * id.Then gives a success message that the video was added.Adds the action
	 * done to the action log.If the user is null, ie is no logged in , he will be redirected
	 * to the not logged in page.
	 * 
	 * 
	 * @author Hesham Massoud
	 * 
	 * @param ideaId
	 *            to get the ID of the idea which will have a video added to it.
	 * 
	 * @param video
	 *            the code of the video that is going to be added to the idea.
	 */
	public static void addVid(String video, long ideaId) {
		User user = User.getUserInfo(session.get("username"));
		if(user!=null){
		Idea idea = Idea.findById(ideaId);
		notFoundIfNull(idea);
		if (video.contains("http://www.youtube.com/")) {
			int i = 0;
			boolean containsAnd = false;
			// "http://www.youtube.com/embed/ZpUYjpKg9KY"
			String[] link = video.split("/");
			for (i = 0; i < link.length; i++) {
				if (link[i].contains("=") && link[i].contains("&")) {
					containsAnd = true;
					break;
				} else {
					if (link[i].contains("="))
						break;
				}
			}
			String r = link[i];
			for (int j = 0; j < r.length(); j++) {
				if (r.charAt(j) == '=') {
					i = j;
					break;
				}
			}
			if (!containsAnd)
				idea.videos.add(r.substring(i + 1, r.length()));
			else {
				int z = 0;
				for (z = 0; z < r.length(); z++) {
					if (r.charAt(z) == '&') {
						break;
					}
				}
				idea.videos.add(r.substring(i + 1, z));
			}
			idea.save();
			
			String actionMsg = user.userName
			+ " added a video to the idea "+ idea.title + ".";
			new ActionLog(actionMsg, user, null).save();
			flash.success("Video Added Successfully.");
			IdeaController.viewAddVideo(idea.id);
		} else {
			flash.error("Please enter a valid youtube video URL");
			IdeaController.viewAddVideo(idea.id);
		}
	}
		else{
			render("Apllication/notLoggedIn.html");
		}
	}

	/**
	 * a method to render the topic ID where the idea will be posted
	 * 
	 * @param topicID
	 *            the ID of the topic where the ID will be posted
	 */

	public static void viewPostIdea(Long topicID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			render(topicID);
		} else {
			render("Application/notLoggedIn.html");
		}

	}

	/**
	 * A method to post an idea in a specific topic or save the idea as a draft.
	 * Depends on which button was clicked on the form in the view
	 * 'addTopic.html'.
	 * 
	 * @author AhmedMustafaTaha
	 * @author Hesham Massoud
	 * 
	 * @param topicID
	 *            to get the ID of the topic where the idea will be posted
	 * @param title
	 *            to get the title of the idea from the user
	 * @param content
	 *            to get the content of the idea from the user
	 * @param save
	 *            to submit and save the idea in the data base
	 * @param saveDraft
	 *            to save the idea as a draft
	 */

	public static void postIdea(Long topicID, String title, String content,
			String save, String saveDraft) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Topic topic = Topic.findById(topicID);
			// long userID = user.id;
			if ((save != null && !save.isEmpty())) {
				validation.required(title).message("Idea title is required!");
				// validation.required(content).message("please add content to your idea!");
				if (validation.hasErrors()) {
					params.flash();
					validation.keep();
					viewPostIdea(topicID);
				} else {
					topic.addIdea(title, content, new Date(), user);
					Idea idea = topic.ideas.get(topic.ideas.size() - 1);
					String actionLogMessage = "User name : " + user.name+ " added a new idea with title : " + idea.title +" in Topic : "  + topic.name;
					new ActionLog(actionLogMessage,user,null).save();
					Browse.viewTopic(topicID);

				}
			} else {

				validation.required(title).message("Idea title is required!");
				if (validation.hasErrors()) {
					params.flash();
					validation.keep();
					viewPostIdea(topicID);
				} else {
					topic.saveIdeaAsDraft(title, content, new Date(), topic,
							user);
					String actionMsg = user.userName
					+ " saved a draft idea with the title " + title + ".";
					new ActionLog(actionMsg, user, null).save();
					flash.success("Idea Successfully saved as draft.");
					flash.success("Idea Successfully saved as draft.");
					ProfileController.myDrafts();
				}
			}
		} else {
			render("Application/notLoggedIn.html");
		}

	}

	/**
	 * to render the entity ID where the topic will be posted
	 * 
	 * @param entityID
	 *            to get the entity ID where the topic will be posted
	 */

	public static void viewPostTopic(long entityID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			render(entityID);
		} else {
			render("Application/notLoggedIn.html");
		}
	}

	/**
	 * a method used to post a topic to a specific entity
	 * 
	 * @author AhmedMustafaTaha
	 * 
	 * @param name
	 *            name of the topic to be added to the entity
	 * @param description
	 *            description of the topic to be added to the entity
	 * @param entityID
	 *            the ID of the entity where the topic will be added
	 */

	public static void postTopic(String name, String description, long entityID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			validation.required(name).message("Topic name is required!");
			validation.required(description).message(
					"please add description to your topic!");
			if (validation.hasErrors()) {
				params.flash();
				validation.keep();
				viewPostTopic(entityID);
			} else {
				EEntity entity = EEntity.findById(entityID);
				entity.addTopic(name, 0, description, entity, user);
				Topic topic = entity.topics.get(entity.topics.size() - 1);
				String actionLogMessage = "User name : " + user.name+ " added a new topic with title : " + topic.name +" in entity : "  + entity.name;
				new ActionLog(actionLogMessage,user,null).save();
				Browse.viewEntity(entityID);
			}
		} else
			render("Application/notLoggedIn.html");

	}

	/**
	 * create a method to add a topic to an entity using the postTopic method,
	 * this is called from the viewEntity.html file
	 * 
	 * @param id, id of the entity to which the topic will be added 
	 * @author Omar Fouda
	 */
	public static void addTopic(long id) {
		render(id); 
	}

	/**
	 * A method to render the ID of the entity that a topic can be requested on.
	 * 
	 * @param entityID
	 *            is the ID of the entity that a topic can be requested on.
	 * */
	public static void viewCreateRequest(long entityID) {
		render(entityID);
	}

	/**
	 * This method enables the user to send a request to create a topic in a
	 * certain entity or save it as a draft. It takes the name and the
	 * description of the requested topic, 2 strings which represent two submits
	 * in a form and the ID of the entity the topic is requested in. This method
	 * checks whether the button that was clicked was "Send the Topic Request"
	 * or "Save request as draft". And it performs the corresponding operation
	 * to the clicked button.
	 * 
	 * @author Hesham Massoud
	 * @author Hablas
	 * @param name
	 *            is the name of the requested topic.
	 * @param description
	 *            is the description of the requested topic.
	 * @param entityID
	 *            is the ID of the entity the request is made in.
	 * @param save
	 *            is the String which represents the "Send Request" button.
	 * @param saveDraft
	 *            is the String which represents the "Save as Draft" button.
	 * 
	 * */
	public static void sendRequest(String name, String description,
			long entityID, String save, String saveDraft) {
		String username = session.get("username");
		User user = User.find("byUsername", username).first();
		if(user!=null){
		EEntity entity = EEntity.findById(entityID);
		if ((save != null && !save.isEmpty())) {
			flash.success("Request Successfully sent.");
			entity.postRequest(name, description, user);
			Browse.viewEntity(entityID);

		} else {
			long rqstId = entity.saveRequestDraft(name, description, user);
			String actionMsg = user.userName
			+ " saved a topic request with the title " + name + ".";
			new ActionLog(actionMsg, user, null).save();
			flash.success("Idea Successfully saved as draft.");
			flash.success("Request Successfully saved as draft.");
			ProfileController.myDrafts();
			// Redirect to next page.
		}
		}
		else{
			render("Application/notLoggedIn.html");
		}
	}

	/**
	 * a method used to render the topic ID, to be used in viewing the page of
	 * tagging a topic
	 * 
	 * @param topicID
	 *            id of the topic to be passed to the HTML page
	 */

	public static void viewTagTopic(long topicID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null)
			render(topicID);
		else
			render("Application/notLoggedIn.html");
	}

	/**
	 * a method used to add a tag to a specific topic, by taking the ID of the
	 * topic and the name of the tag, it creates the tag and then add it to the
	 * topic
	 * 
	 * @author AhmedMustafaTaha
	 * 
	 * @param topicID
	 *            ID of the topic where the tag will be added
	 * @param name
	 *            name of the tag to be created and then added to the topic
	 */

	public static void tagTopic(Long topicID, String name) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Topic topic = Topic.findById(topicID);
			topic.addTag(name);
			topic.save();
			String actionLogMessage = "User name : " + user.name+ " tagged the topic : " + topic.name +" with : "  + name;
			new ActionLog(actionLogMessage,user,null).save();
			Browse.viewTopic(topicID);
		} else
			render("Application/notLoggedIn.html");
	}

	/**
	 * A method that given a tag removes it from a topic
	 * 
	 * @author Shady
	 * @param entityID
	 *            The id of the entity the topic belongs to
	 * @param topicID
	 *            The id of the topic the tag and topic belongs to
	 * @param tagID
	 *            The id of the tag which will be removed
	 * @see List of topics page
	 */
	public static void unTagTopic(long entityID, long topicID, long tagID) {

		String userName = session.get("username");
		User user = User.find("userName", userName).first();

		if (user != null) {
			Topic.unassignTag(user.id, entityID, topicID, tagID);
			Browse.viewTopic(topicID);
		}

	}

	/**
	 * A method that will display a form so that the user can enter a name in it
	 * for the tag's new name
	 * 
	 * @author Shady
	 * @param entityID
	 *            The id of the entity the topic belongs to
	 * @param topicID
	 *            The id of the topic the tag and topic belongs to
	 * @param tagID
	 *            The id of the tag which will be renamed
	 * @see A form where the user can enter a new name
	 * 
	 */
	public static void renameTag(long entityID, long topicID, long tagID) {
		String userName = session.get("username");
		User user = User.find("userName", userName).first();

		if (user != null) {
			EEntity entity = EEntity.findById(entityID);
			Topic topic = Topic.findById(topicID);
			Tag tag = Tag.findById(tagID);

			if (entity.getOrganizers().contains(user)
					|| entity.organization.getOrganizationLead().equals(user)
					|| entity.organization.isAsOrganizationLead(user.id)
					|| user.isSysteAdmin()) {
				render(entity, topic, tag);
			}
		}

	}

	/**
	 * A method that will rename a tag to a new name
	 * 
	 * @author Shady
	 * @param entityID
	 *            The id of the entity the topic belongs to
	 * @param topicID
	 *            The id of the topic the tag and topic belongs to
	 * @param tagID
	 *            The id of the tag which will be renamed
	 * @param newName
	 *            The new name of the tag
	 * @see The list of topics
	 * 
	 */
	public static void renameTagForm(long entityID, long topicID, long tagID,
			String newName) {
		String userName = session.get("username");
		User user = User.find("userName", userName).first();

		if (newName == null || newName.isEmpty())
			Browse.viewTopic(topicID);
		else if (user != null) {
			EEntity entity = EEntity.findById(entityID);
			Topic topic = Topic.findById(topicID);
			Tag tag = Tag.findById(tagID);

			if (entity.getOrganizers().contains(user)
					|| entity.organization.getOrganizationLead().equals(user)
					|| entity.organization.isAsOrganizationLead(user.id)
					|| user.isSysteAdmin()) {
				Topic.renameTag(user.id, entityID, topicID, tagID, newName);
				Browse.viewTopic(topicID);
			}
		}
	}

	/**
	 * a method used to render the idea ID to be used in viewing the page
	 * responsible for tagging an idea, it also passed boolean triedToCreate to
	 * check if an idea developer tried to create a tag and the organization
	 * preferences does not allow such an action
	 * 
	 * @param ideaID
	 *            the ID of the idea where the tag will be added
	 * @param triedToCreate
	 *            boolean to check whether an idea developer tried to create a
	 *            tag or not
	 */

	public static void viewTagIdea(long ideaID, boolean triedToCreate) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Idea idea = Idea.findById(ideaID);
			List<String> tags = new ArrayList<String>();
			for(int i=0; i<Tag.getListOfAllTags().size(); i++)
				tags.add(Tag.getListOfAllTags().get(i).name);
			List<Tag> allTags = new ArrayList<Tag>(idea.tags);
			render(ideaID, triedToCreate, allTags, tags);
		} else
			render("Application/notLoggedIn.html");
	}

	/**
	 * a method used to add a tag to a certain idea
	 * 
	 * @author AhmedMustafaTaha
	 * 
	 * @param ideaID
	 *            the ID of the idea to be tagged
	 * @param name
	 *            the name of the tag to be created and then added to the idea
	 */

	public static void tagIdea(Long ideaID, String name) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Idea idea = Idea.findById(ideaID);
			Organization org = idea.topic.entity.organization;
			if (!user.isOrganizationLead(org.id)
					&& !user.isOrganizer(idea.topic.entity.id)
					&& !org.allowingTagCreationForDevelopers) {
				Tag tag = Tag.find("byName", name).first();
				if (tag == null) {
					TopicController.viewTagIdea(idea.id, true);
					// print you are not allowed to create a tag
				} else {
					if(!name.isEmpty())
						idea.addTag(name);
					String actionLogMessage = "User name : " + user.name+ " tagged the idea : " + idea.title +" with : "  + name;
					new ActionLog(actionLogMessage,user,null).save();
					TopicController.viewTagIdea(idea.id,false);
				}
			} else {
				if(!name.isEmpty())
					idea.addTag(name);
				String actionLogMessage = "User name : " + user.name+ " tagged the idea : " + idea.title +" with : "  + name;
				new ActionLog(actionLogMessage,user,null).save();
				TopicController.viewTagIdea(idea.id,false);
			}
		} else
			render("Application/notLoggedIn.html");
	}

	/**
	 * it's the method called from the View of the topicRating UI.
	 * 
	 * @param rating
	 *            the rating chosen by the user
	 * @param topicId
	 *            the id of the rated topic
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static void rateTopic(int rating, long topicId) {
		String userName = session.get("username");
		notFoundIfNull(userName);

		validation.range(rating, 1, 5);
		validation.range(topicId, 1, Topic.count());
		if (validation.hasErrors()) {
			notFound("Error with id of the topic or the rating range");
		}

		User user = User.getUserInfo(userName);
		Topic topic = Topic.findById(topicId);
		if (topic == null || user == null) {
			notFound();
		}

		boolean isAuthorized = false;
		if (topic.entity.organization.isPrivate()
				|| topic.entity.organization.isSecret()) {
			if (topic.entity.organization.isMember(user.id)) {
				isAuthorized = true;
			} else {
				isAuthorized = false;
			}
		} else {
			isAuthorized = true;
		}
		if (isAuthorized) {
			addOrUpdateRating(topic, user, rating); // no data yet.
			renderText((int) topic.topicRating);
		} else {
			forbidden();
		}
	}

	/**
	 * the method takes a rating and the user who chose this rating and the
	 * rated topic and update the rating if the topic was already rated by this
	 * user or add the new rating if it wasn't rated by this user be4
	 * 
	 * @param topic
	 *            the topic that will be rated
	 * @param user
	 *            the rating user
	 * @param newUserRating
	 *            the new rating chosen by the user.
	 * @return true if it's new Rating. False if it's changing rating.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean addOrUpdateRating(Topic topic, User user,
			int newUserRating) {
		boolean isAuthorized = false;
		if (topic.entity.organization.isPrivate()
				|| topic.entity.organization.isSecret()) {
			if (topic.entity.organization.isMember(user.id)) {
				isAuthorized = true;
			} else {
				isAuthorized = false;
			}
		} else {
			isAuthorized = true;
		}

		if (!isAuthorized) {
			return false;
		}
		user = User.findById(user.id);
		topic = Topic.findById(topic.id);
		List<TopicRating> topicRatings = user.topicsRatings;
		for (TopicRating topicRating : topicRatings) {
			if (topicRating.topic.id == topic.id) { // if true then it's nt new
				double newTopicRating = calculateChangedRating(topicRating,
						newUserRating); // rating

				topicRating.updateRating(newUserRating, newTopicRating);// the
																		// user's
																		// rating
				return false;
			}
		}
		// the rating is new.
		new TopicRating(topic, user, newUserRating).save();
		double rating = calculateNewRating(topic, newUserRating);
		topic.updateRating(rating);// the whole value
		return true;
	}

	/**
	 * the method adds the new rating to the topic Rating.
	 * 
	 * @param topic
	 *            the rated topic.
	 * @param newRating
	 *            the new rating will be added
	 * @return returns the new rating for the topic.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateNewRating(Topic topic, int newRating) {
		int n = topic.usersRatings.size();
		return (((n - 1) * topic.topicRating) + newRating) / ((n - 1) + 1);
	}

	/**
	 * the method calculates the new rating for the topic after changing one of
	 * its previous ratings
	 * 
	 * @param topicRating
	 *            the topicRating object that contains the rated topic, the old
	 *            rating, and the rating user.
	 * @param newRating
	 *            the new rating chose by the user
	 * @return the new calculated rating for the topic.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateChangedRating(TopicRating topicRating,
			int newRating) {
		int n = topicRating.topic.usersRatings.size();
		double rating = topicRating.topic.topicRating;
		int oldRating = topicRating.rating;
		return ((n * rating) - oldRating + newRating) / n;
	}

	/**
	 * a method to delete an idea from a topic, then it redirects the user to
	 * the topic page
	 * 
	 * @author AhmedMustafaTaha
	 * @param topicID
	 *            the id of the topic of the removed idea
	 * @param ideaID
	 *            the id of the idea to be deleted
	 */

	public static void deleteIdea(long topicID, long ideaID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Topic topic = Topic.findById(topicID);
			Idea idea = Idea.findById(ideaID);
			String actionLogMessage = "User name : " + user.name+ " deleted the idea : " + idea.title +" from topic : "  + topic.name;
			new ActionLog(actionLogMessage,user,null).save();
			topic.deleteIdea(ideaID);
			Browse.viewTopic(topicID);
		} else {
			render("Application/notLoggedIn.html");
		}
	}

	/**
	 * a method to change the status of a topic to active or inactive
	 * 
	 * @author AhmedMustafaTaha
	 * 
	 * @param topicID
	 *            The ID of the topic to be changed
	 */

	public static void showTopic(long topicID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Topic topic = Topic.findById(topicID);
			topic.showTopic();
			String msg = "The topic : "+topic.name+" is now shown";
			List<User> users = new ArrayList<User>(topic.followingUsers);
			for(int i=0; i<topic.ideas.size(); i++) {
				if(!users.contains(topic.ideas.get(i).creator)){
					users.add(topic.ideas.get(i).creator);
				}
			}
			Application.sendMail(msg, (topic.name+" is now shown"), users);
			String actionLogMessage = "User name : " + user.name+ " has changed the status of the topic : " + topic.name +" to shown ";
			new ActionLog(actionLogMessage,user,null).save();
			Browse.viewTopic(topicID);
		} else
			render("Application/notLoggedIn.html");

	}

	/**
	 * a method to change the status of a topic to hidden
	 * 
	 * @author AhmedMustafaTaha
	 * 
	 * @param topicID
	 *            The ID of the topic to be changed
	 */

	public static void hideTopic(long topicID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Topic topic = Topic.findById(topicID);
			topic.hideTopic();
			String msg = "Sorry the topic : "+topic.name+" is now hidden";
			List<User> users = new ArrayList<User>(topic.followingUsers);
			for(int i=0; i<topic.ideas.size(); i++) {
				if(!users.contains(topic.ideas.get(i).creator)){
					users.add(topic.ideas.get(i).creator);
				}
			}
			Application.sendMail(msg, (topic.name+" is now hidden"), users);
			String actionLogMessage = "User name : " + user.name+ " has changed the status of the topic : " + topic.name +" to hidden ";
			new ActionLog(actionLogMessage,user,null).save();
			
			Browse.viewTopic(topicID);
		} else
			render("Application/notLoggedIn.html");

	}

	/**
	 * a method used to remove a tag from an idea
	 * 
	 * @author AhmedMustafaTaha
	 * @param ideaID
	 *            the ID of the idea to be tagged
	 * @param name
	 *            the name of the tag to be created and then added to the idea
	 */

	public static void removeTagIdea(Long ideaID, Long tagID) {
		User user = User.getUserInfo(session.get("username"));
		if (user != null) {
			Idea idea = Idea.findById(ideaID);
			Tag tag = Tag.findById(tagID);
			String actionLogMessage = "User name : " + user.name+ " removed the tag : " + tag.name +" from the idea : "  + idea.title;
			new ActionLog(actionLogMessage,user,null).save();
			idea.removeTag(tagID);
			TopicController.viewTagIdea(ideaID,false);
		} else
			render("Application/notLoggedIn.html");

	}

	/**
	 * renders a list of Top featured topics according to this users
	 * preferences/
	 * 
	 * @author Ahmed
	 */
	public static void getFeaturedTopics() {
		String username = session.get("username");
		notFoundIfNull(username);
		User user = User.getUserInfo(username);
		notFoundIfNull(user);
		List<Topic> featuredTopics = new ArrayList<Topic>();
		for (Topic topic : user.featuredTopics) {
			if (topic.entity.organization.isSecret()) {
				if (topic.entity.organization.isMember(user.id)
						&& topic.isAllowedToBeViewedToIdeaDevelopers()) {
					featuredTopics.add(topic);
				}
			} else if (topic.isAllowedToBeViewedToIdeaDevelopers()) {
				featuredTopics.add(topic);
			}
		}
		boolean isTopics = true;
		render("Application/Featured.html", featuredTopics, isTopics);
	}

}